/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*-  */
/*
 * g-apk-object.c
 * Copyright (C) 2014 Weiketing <weikting@gmail.com>
 *
 * gtkapkmanager is free software: you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * gtkapkmanager is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License along
 * with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <config.h>
#include "gapkobject.h"
#include <time.h>
#include "common-glue.h"


struct _GApkObjectPrivate
{
	gchar *apk_file;
	gchar *app_name;
	gchar *package_name;
	gchar *version_name;
	long  version_code;
	gchar *icon_file;
	long  apk_size;
    GdkPixbuf *icon;

	gboolean isOpened;
};

typedef struct
{
	GApkObject *object;
	gchar *message;
	gboolean isOk;
}OpenResultIdleData;

typedef struct{
	GApkObject *object;
	gpointer   user_data;
	GApkObjectInstallCallback func;
	gchar *device_serial;
	gchar *message;
	gboolean isOk;
}GApkObjectInstallCallbackData;

static inline void OpenResultIdleData_free(OpenResultIdleData *d){
	if(d == NULL)return;
	g_free (d->message);
	g_free(d);
}

static inline OpenResultIdleData* OpenResultIdleData_new(){
	return g_new0(OpenResultIdleData,1);
    
}

static inline void GApkObjectInstallCallbackData_free(GApkObjectInstallCallbackData *d){
	if(d == NULL)return;
	g_free (d->message);
	g_free(d->device_serial);
	g_free(d);
}

static inline GApkObjectInstallCallbackData* GApkObjectInstallCallbackData_new(){
	return g_new0(GApkObjectInstallCallbackData,1);
}

static inline const gchar* get_apk_info_shell_path()
{
    static gchar *ret = NULL;
	if(ret == NULL){
		if(g_file_test ("./src/get_apk_info.sh",G_FILE_TEST_IS_REGULAR)){
			ret  = "./src/get_apk_info.sh";
		}else {
			ret = PACKAGE_DATA_DIR "/get_apk_info.sh";
		}
	}
	return ret;
}


enum
{
	SIGNAL_OPEN_RESULT,
    SIGNAL_LAST
};


static guint g_apk_object_signals[SIGNAL_LAST] = {0};

G_DEFINE_TYPE (GApkObject, g_apk_object, G_TYPE_OBJECT);

static void
g_apk_object_init (GApkObject *g_apk_object)
{
	g_apk_object->priv = G_TYPE_INSTANCE_GET_PRIVATE (g_apk_object, G_APK_TYPE_OBJECT, GApkObjectPrivate);
	g_apk_object->priv->isOpened = FALSE;

	/* TODO: Add initialization code here */
}

static void
g_apk_object_finalize (GObject *object)
{
	/* TODO: Add deinitalization code here */

	G_OBJECT_CLASS (g_apk_object_parent_class)->finalize (object);

	g_apk_object_close(G_APK_OBJECT(object));
}

static void
g_apk_object_class_init (GApkObjectClass *klass)
{
	GObjectClass* object_class = G_OBJECT_CLASS (klass);

	g_type_class_add_private (klass, sizeof (GApkObjectPrivate));

	object_class->finalize = g_apk_object_finalize;

	g_apk_object_signals[SIGNAL_OPEN_RESULT] = g_signal_new ("open-result",
	                                                    G_APK_TYPE_OBJECT,
														G_SIGNAL_RUN_FIRST,
	                                                    G_STRUCT_OFFSET(GApkObjectClass,open_result),
                 NULL,NULL,
                 g_apk_object_common_marshal_VOID__INT_STRING,
                 G_TYPE_NONE,
                 2,
	             G_TYPE_BOOLEAN,G_TYPE_STRING
	               );

    g_random_set_seed(time(NULL));
}


static gboolean on_open_result(OpenResultIdleData *d){

	d->object->priv->isOpened = d->isOk;
	g_signal_emit(d->object,g_apk_object_signals[SIGNAL_OPEN_RESULT],0,d->isOk,d->message );

	OpenResultIdleData_free (d);
	return FALSE;
}

static gpointer
g_apk_object_parser_thread(GApkObject *self)
{
	OpenResultIdleData *idleData = OpenResultIdleData_new();
    static const gchar* InfoGroup = "ApkInfo";
    gchar *tmp_keyfile = g_strdup_printf("%s%s.%u_%u.ini",
                                    g_get_tmp_dir(),
                                    G_DIR_SEPARATOR_S,
                                    getuid(),
                                    g_random_int());
    int st = 0;
    gchar *cmd = g_strdup_printf("'%s' '%s' '%s'",
        get_apk_info_shell_path(),
        self->priv->apk_file,
        tmp_keyfile);
	idleData->isOk = FALSE;
	if(g_spawn_command_line_sync(cmd,NULL,NULL,&st,NULL) && st == 0){
        GKeyFile *keyfile = g_key_file_new();
        if(g_key_file_load_from_file(keyfile,tmp_keyfile,0,NULL)){
            self->priv->package_name = g_key_file_get_string(keyfile,InfoGroup,"name",NULL);
            self->priv->version_name = g_key_file_get_string(keyfile,InfoGroup,"versionName",NULL);
			self->priv->version_code = g_key_file_get_uint64 (keyfile,InfoGroup,"versionCode",NULL);
            self->priv->app_name = g_key_file_get_locale_string(keyfile,InfoGroup,"application-label",NULL,NULL);
            gchar *icon_name =  g_key_file_get_string(keyfile,InfoGroup,"application-icon",NULL);
            
            gchar *unzip_dir = g_strdup_printf("%s%s.%u",
                                        g_get_tmp_dir(),
                                        G_DIR_SEPARATOR_S,
                                        getuid()
                                        );
            g_mkdir_with_parents(unzip_dir,0700);
            gchar *unzip_cmd = g_strdup_printf("unzip -o '%s' %s -d %s",
                                            self->priv->apk_file,
                                            icon_name,
                                            unzip_dir);
			gchar *err = NULL;
			gchar *out = NULL;
            g_spawn_command_line_sync(unzip_cmd,&out,&err,&st,NULL);
			g_free(err);
			g_free(out);

			self->priv->icon_file = g_strdup_printf("%s%s%s",unzip_dir,G_DIR_SEPARATOR_S,icon_name);

            g_free(icon_name);
            g_free(unzip_dir);
            g_free(unzip_cmd);

			idleData->message = g_strdup("OK");
			idleData->isOk =  TRUE;
        }else{
			idleData->message = g_strdup("Get apk info Error");
		}
        
        g_key_file_free(keyfile);
    }else{
		idleData->message = g_strdup("apk file Error");
	}
    ///g_print("cmd:%s\n",cmd);
	g_unlink (tmp_keyfile);
	g_free (cmd);
	g_free(tmp_keyfile);
    idleData->object = self;
	g_idle_add (on_open_result,idleData);
    return NULL;
}

 void 
g_apk_object_close(GApkObject *self)
{
	self->priv->isOpened = FALSE;
	g_free (self->priv->apk_file);
	g_free(self->priv->app_name);
	g_free (self->priv->package_name);
	g_free (self->priv->version_name);
	g_free (self->priv->icon_file);

	self->priv->apk_file = NULL;
	self->priv->app_name = NULL;
	self->priv->package_name = NULL;
	self->priv->version_name = NULL;
	self->priv->icon_file = NULL;
    
    if(self->priv->icon){
        g_object_unref(self->priv->icon);
        self->priv->icon = NULL;
    }

}

gboolean 
g_apk_object_open(GApkObject *self,const char *apk_file)
{
	gboolean ret = FALSE;
	g_apk_object_close (self);
	self->priv->apk_file = g_strdup(apk_file);
	GThread *thread = g_thread_new("open",g_apk_object_parser_thread,self);
	g_thread_unref (thread);
	return ret;
	
}


GdkPixbuf*
g_apk_object_get_icon(GApkObject *self)
{
    if(self->priv->icon_file && !self->priv->icon){
        self->priv->icon = gdk_pixbuf_new_from_file(self->priv->icon_file,NULL);
    }
    return self->priv->icon;
}

const gchar*
g_apk_object_appname(GApkObject *self)
{
    return self->priv->app_name;
}

const gchar*
g_apk_object_package_name(GApkObject *self)
{
    return self->priv->package_name;
}

long
g_apk_object_version_code(GApkObject *self)
{
    return self->priv->version_code;
}

long
g_apk_object_apk_size(GApkObject *self)
{
    return self->priv->apk_size;
}

const gchar*
g_apk_object_version_name(GApkObject *self)
{
    return self->priv->version_name;
}

void 
g_apk_object_print(GApkObject *self)
{
	g_printf ("file:%s\n",self->priv->apk_file);
	g_printf ("    application :%s\n",self->priv->app_name);
	g_printf ("    package     :%s\n",self->priv->package_name);
	g_printf ("    version     :%s\n",self->priv->version_name);
    g_printf ("    versionCode :%d\n",self->priv->version_code);
	g_printf ("    icon_file   :%s\n",self->priv->icon_file);
}


static gboolean
on_install_finished(GApkObjectInstallCallbackData *data)
{
	data->func(data->object,data->isOk,data->message,data->user_data);

	GApkObjectInstallCallbackData_free(data);
	return FALSE;
}

gpointer
g_apk_object_install_thread(GApkObjectInstallCallbackData *data)
{
	gint st = -1;
	gchar *msg = NULL;
	st = adb_utils_install(data->device_serial,data->object->priv->apk_file,&msg);
	data->message = msg;
	data->isOk = (st == 0);
	g_idle_add (on_install_finished,data);
	return NULL;
}

void
g_apk_object_install(GApkObject *self,const gchar *device_serial,GApkObjectInstallCallback func ,gpointer data)
{
	if(!self->priv->isOpened){
		func(self,FALSE,"Must open an apk file",data);
		return;
	}
	GApkObjectInstallCallbackData *dd = GApkObjectInstallCallbackData_new();
	dd->object = self;
	dd->device_serial = g_strdup(device_serial);
	dd->func = func;
	dd->user_data = data;
	GThread *th = g_thread_new ("install",g_apk_object_install_thread,dd);
	g_thread_unref (th);
}

gboolean
g_apk_object_is_opened(GApkObject *self)
{
	return self->priv->isOpened;
}

GApkObject*
g_apk_object_new(){
	return g_object_new (G_APK_TYPE_OBJECT,NULL);
}
